package com.cdn.cretry.component;

/**
 * 蔡定努
 * 2024/06/06 12:53
 */

import com.cdn.cretry.strategy.DelayStrategy;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

@Slf4j
public class RetryComponent {


    /**
     * 优雅的重试逻辑实现
     *
     * @param supplier      尝试执行的操作，返回true表示成功，false或其他异常表示失败
     * @param maxRetries    最大重试次数
     * @param initialDelay  初始延迟时间，单位毫秒,如果是指数增长，这则是指数
     * @param delayStrategy 延迟策略，如固定延迟、指数退避等
     * @return 成功执行的结果
     */
    public static <T> T retry(Supplier<T> supplier, int maxRetries, long initialDelay, DelayStrategy delayStrategy) {
        try {
            return supplier.get();
        } catch (Exception e) {
            for (int attempt = 1; attempt <= maxRetries; attempt++) {
                long delay = delayStrategy.calculateDelay(attempt, initialDelay);
                log.warn("Retry attempt {}: waiting for {} milliseconds before retry...", attempt, delay);
                sleep(delay);
                try {
                    return supplier.get();
                } catch (Exception retryException) {
                    if (attempt >= maxRetries) {
                        throw retryException;
                    }
                }
            }
        }
        throw new IllegalStateException("Retry method should have exited before this line.");
    }


    private static void sleep(long delay) {
        try {
            TimeUnit.MILLISECONDS.sleep(delay);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException("线程中断", e);
        }
    }

}
